Skip to content

Conversation

@mr-lee
Copy link
Member

@mr-lee mr-lee commented Sep 26, 2025

Resuming #865

Description

  • Add AgentConfig class for loading configuration from JSON files or dicts
  • Support model, prompt, and tools configuration options

Goal of this feature:

  • Start the centralization of serializing the agent config from a file. This currently exists in the tools repo, for spawning sub-agents: https://github.com/strands-agents/tools/blob/main/src/strands_tools/utils/models/model.py
    • More strands features will be represented in this feature in follow up pull requests
    • We have at least one more upcoming feature that will take advantage of this feature
  • Make sharing of agents easier: This isnt the most readable format, but we can convert a front matter markdown to a json dict, and then validate the schema using this definition in the future

Usage example

For basic usage with the default set of tools available to choose from the config: file_read, editor, http_request, use_agent, and shell

from strands.experimental import config_to_agent

agent = config_to_agent({"model": "test-model", "prompt": "Test prompt", "tools": ["strands_tools.file_read", "strands_tools.shell"]}, description="My custom description") # everything after config arg is passed to the agent constructor as kwargs

You can also load a config from a file:

from strands.experimental import AgentConfig

config = AgentConfig("file://path/to/local/config) # Config gets loaded into dict
agent = config.to_agent() # kwargs are passed to the agent init

Documentation PR

strands-agents/docs#252

Type of Change

New feature

Testing

How have you tested the change? Verify that the changes do not break functionality or introduce warnings in consuming repositories: agents-docs, agents-tools, agents-cli

  • I ran hatch run prepare

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Copy link
Member

@awsarron awsarron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

proposed interface during experimental:

from strands.experimental import config_to_agent

agent = config_to_agent("/path/to/amazing-agent.json")

agent("do the thing")

potential interface for non-experimental in future releases:

from strands import config_to_agent

agent = config_to_agent("/path/to/amazing-agent.json")

agent("do the thing")

example amazing-agent.json definition of tools:

{
  // ...
  tools: ["strands_tools.file_read", "my_app.tools.cake_tool", "/path/to/another_tool.py"]
}

strands supports loading tools from python modules and filepaths:

def add_tool(tool: Any) -> None:
# Case 1: String file path
if isinstance(tool, str):
# Extract tool name from path
tool_name = os.path.basename(tool).split(".")[0]
self.load_tool_from_filepath(tool_name=tool_name, tool_path=tool)
tool_names.append(tool_name)
# Case 2: Dictionary with name and path
elif isinstance(tool, dict) and "name" in tool and "path" in tool:
self.load_tool_from_filepath(tool_name=tool["name"], tool_path=tool["path"])
tool_names.append(tool["name"])
# Case 3: Dictionary with path only
elif isinstance(tool, dict) and "path" in tool:
tool_name = os.path.basename(tool["path"]).split(".")[0]
self.load_tool_from_filepath(tool_name=tool_name, tool_path=tool["path"])
tool_names.append(tool_name)
# Case 4: Imported Python module
elif hasattr(tool, "__file__") and inspect.ismodule(tool):
# Get the module file path
module_path = tool.__file__
# Extract the tool name from the module name
tool_name = tool.__name__.split(".")[-1]
# Check for TOOL_SPEC in module to validate it's a Strands tool
if hasattr(tool, "TOOL_SPEC") and hasattr(tool, tool_name) and module_path:
self.load_tool_from_filepath(tool_name=tool_name, tool_path=module_path)
tool_names.append(tool_name)
else:
function_tools = self._scan_module_for_tools(tool)
for function_tool in function_tools:
self.register_tool(function_tool)
tool_names.append(function_tool.tool_name)
if not function_tools:
logger.warning("tool_name=<%s>, module_path=<%s> | invalid agent tool", tool_name, module_path)
# Case 5: AgentTools (which also covers @tool)
elif isinstance(tool, AgentTool):
self.register_tool(tool)
tool_names.append(tool.tool_name)
# Case 6: Nested iterable (list, tuple, etc.) - add each sub-tool
elif isinstance(tool, Iterable) and not isinstance(tool, (str, bytes, bytearray)):
for t in tool:
add_tool(t)
else:
logger.warning("tool=<%s> | unrecognized tool specification", tool)

for the initial implementation in this PR we could do something like:

def config_to_agent(filepath: str) -> Agent:
    # pseudo code
    parsed_config = JSON.loads(filepath)
    tools_list = []
    for tool in parsed_config["tools"]:
        tool_arg = tool
        if not is_filepath(tool):
            try:
                tool_arg = importlib.import_module(tool)
            except ImportError as e:
                # handle tool not a file and not a module
        tools_list.append(tool_arg)
    return Agent(tools=tools_list)

@mr-lee mr-lee force-pushed the feature/agent-config-squashed branch from 832b290 to f372666 Compare September 26, 2025 22:34
@mr-lee mr-lee force-pushed the feature/agent-config-squashed branch from 27bb82f to c2d1baa Compare September 26, 2025 22:40
@Unshure Unshure self-assigned this Sep 29, 2025
- Add AgentConfig class for declarative agent configuration via JSON/dict
- Support file:// prefix for loading configurations from JSON files
- Implement ToolRegistry integration with automatic default tool loading
- Add raise_exception_on_missing_tool parameter for flexible error handling
- Support tool selection from registry via tool names in config
- Add comprehensive test coverage for all configuration scenarios
- Move hook events from experimental to production with updated names
- Add OpenAI model provider enhancements and Gemini model improvements
- Update event loop and tool executors to use production hook events

🤖 Assisted by Amazon Q Developer
- Reset experimental/__init__.py to not import AgentConfig by default
- This may resolve import issues in CI environments
- AgentConfig can still be imported directly from strands.experimental.agent_config

🤖 Assisted by Amazon Q Developer
- Move JSON schema back to inline variable for simplicity
- Add comprehensive tool validation with helpful error messages
- Validate tools can be loaded as files, modules, or @tool functions
- Add clear documentation about code-based instantiation limitations
- Update module docstring and function comments with usage patterns
- Add test for tool validation error messages
- Remove schemas directory (no longer needed)

🤖 Assisted by Amazon Q Developer
- Fix error message for missing modules to be more descriptive
- Remove redundant 'to properly import this tool' text from error messages
- Add specific error messages for missing modules vs missing functions
- Add unit tests for each error case:
  - Invalid tool (not file/module/@tool)
  - Missing module (module doesn't exist)
  - Missing function (function not found in existing module)
- All 17 tests passing with better error coverage

🤖 Assisted by Amazon Q Developer
- Change error message from 'Tool X not found' to 'Module X not found'
- More accurate since we're trying to import it as a module at this point
- Maintains existing test compatibility and error handling logic

🤖 Assisted by Amazon Q Developer
- Revert previous change from 'Module X not found' back to 'Tool X not found'
- Keep original error message format as requested

🤖 Assisted by Amazon Q Developer
@Unshure Unshure force-pushed the feature/agent-config-squashed branch from da9ff2e to cb507dd Compare October 8, 2025 19:55
@codecov
Copy link

codecov bot commented Oct 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@Unshure Unshure force-pushed the feature/agent-config-squashed branch from 5f3c0a9 to 64a31ab Compare October 8, 2025 20:49
@Unshure Unshure force-pushed the feature/agent-config-squashed branch from 64a31ab to 27cef45 Compare October 8, 2025 20:58
@Unshure Unshure force-pushed the feature/agent-config-squashed branch from 27cef45 to 9f33f62 Compare October 8, 2025 21:04
Copy link
Member

@awsarron awsarron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some follow-ups:

  • Document in code (docstrings) and docs page that it only supports bedrock model ID parameters
  • Document using other model providers (change agent.model after transformation)
  • Track a task for supporting non-bedrock model providers
  • Track a task for moving from experimental to production-ready

@Unshure Unshure dismissed stale reviews from zastrowm and themself October 21, 2025 19:18

Feedback addressed

@Unshure Unshure merged commit b69478b into strands-agents:main Oct 21, 2025
16 of 19 checks passed
@Unshure
Copy link
Member

Unshure commented Oct 21, 2025

Some follow-ups:

* Document in code (docstrings) and docs page that it only supports bedrock model ID parameters

* Document using other model providers (change `agent.model` after transformation)

* Track a task for supporting non-bedrock model providers

* Track a task for moving from experimental to production-ready

Updated the docs to reflect the model provider specification. I also created a follow up task for supporting more model providers: #1064

Here is the task for moving it out of experimental: #1065

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants